template <typename T>
class shared_ptr {
public:
    shared_ptr(T* ptr = nullptr) : m_ptr(ptr), m_refCount(new int(1)) {}

    ~shared_ptr() {
        release();
    }

    shared_ptr(const shared_ptr<T>& other) {
        copy(other);
    }

    shared_ptr(shared_ptr<T>&& other) {
        m_ptr = other.m_ptr;
        m_refCount = other.m_refCount;
        other.m_ptr = nullptr;
        other.m_refCount = nullptr;
    }

    shared_ptr<T>& operator=(const shared_ptr<T>& other) {
        if (this != &other) {
            release();
            copy(other);
        }
        return *this;
    }

    shared_ptr<T>& operator=(shared_ptr<T>&& other) {
        if (this != &other) {
            release();
            m_ptr = other.m_ptr;
            m_refCount = other.m_refCount;
            other.m_ptr = nullptr;
            other.m_refCount = nullptr;
        }
        return *this;
    }

    T& operator*() const {
        return *m_ptr;
    }

    T* operator->() const {
        return m_ptr;
    }

    int use_count() const {
        return *m_refCount;
    }

private:
    void release() {
        (*m_refCount)--;
        if (*m_refCount == 0) {
            delete m_ptr;
            delete m_refCount;
        }
    }

    void copy(const shared_ptr<T>& other) {
        m_ptr = other.m_ptr;
        m_refCount = other.m_refCount;
        (*m_refCount)++;
    }

    T* m_ptr;
    int* m_refCount;
};
